package com.iteaj.iot.server.component;

import com.iteaj.iot.*;
import com.iteaj.iot.codec.SocketMessageDecoder;
import com.iteaj.iot.config.ConnectProperties;
import com.iteaj.iot.message.UnParseBodyMessage;
import com.iteaj.iot.server.AbstractUdpServer;
import com.iteaj.iot.server.UdpServerComponent;
import com.iteaj.iot.server.IotSocketServer;
import io.netty.channel.*;
import io.netty.channel.socket.DatagramPacket;
import org.springframework.beans.BeanUtils;
import org.springframework.core.GenericTypeResolver;

import java.lang.reflect.Constructor;

/**
 * 适配Udp DatagramPacket解码组件
 * @param <M>
 */
public abstract class DatagramPacketDecoderComponent<M extends UnParseBodyMessage> extends UdpServerComponent
        implements IotSocketServer, IotProtocolFactory<M>, SocketMessageDecoder<M, DatagramPacket> {

    private ConnectProperties config;
    private Constructor<M> constructor;
    private UdpServerWrapper udpServerWrapper;
    private ProtocolFactoryDelegation delegation;
    private DatagramPacketSimpleHandle datagramPacketSimpleHandle;

    public DatagramPacketDecoderComponent(int port) {
        this(new ConnectProperties(port));
    }

    public DatagramPacketDecoderComponent(ConnectProperties config) {
        this.config = config;
        this.udpServerWrapper = new UdpServerWrapper(config);
        this.datagramPacketSimpleHandle = new DatagramPacketSimpleHandle();
        this.delegation = new ProtocolFactoryDelegation(this);
    }

    @Override
    public abstract String getName();

    @Override
    public AbstractProtocol get(String key) {
        return this.delegation.get(key);
    }

    @Override
    public AbstractProtocol add(String key, Protocol val) {
        return this.delegation.add(key, val);
    }

    @Override
    public AbstractProtocol remove(String key) {
        return this.delegation.remove(key);
    }

    @Override
    public boolean isExists(String key) {
        return this.delegation.isExists(key);
    }

    @Override
    public Object getStorage() {
        return this.delegation.getStorage();
    }

    @Override
    public int port() {
        return this.config.getPort();
    }

    @Override
    public ConnectProperties config() {
        return this.config;
    }

    @Override
    public ChannelInboundHandlerAdapter getMessageDecoder() {
        return this.datagramPacketSimpleHandle;
    }

    @Override
    protected IotSocketServer createDeviceServer() {
        return this.udpServerWrapper;
    }

    @Override
    protected IotProtocolFactory createProtocolFactory() {
        return this.delegation;
    }

    @Override
    public Protocol add(String key, Protocol protocol, long timeout) {
        return this.delegation.add(key, protocol, timeout);
    }

    @Override
    public void init(Object... args) {
        udpServerWrapper.doInitChannel((ChannelPipeline) args[0]);
    }

    /**
     * 将DatagramPacket解码到UnParseBodyMessage对象
     * 注：此解码方法默认每个包都是完整的报文, 没有存在拆包
     * @param ctx
     * @param in
     * @return
     * @throws Exception
     */
    @Override
    public M decode(ChannelHandlerContext ctx, DatagramPacket in) throws Exception {
        final int readableBytes = in.content().readableBytes();
        byte[] message = new byte[readableBytes];
        in.content().readBytes(message);

        return this.newInstantiateMessage(this.constructor, message);
    }

    protected M newInstantiateMessage(Constructor<M> constructor, byte[] message) {
        return BeanUtils.instantiateClass(constructor, message);
    }

    @Override
    public Class<M> getMessageClass() {
        Class<M> aClass = (Class<M>) GenericTypeResolver.resolveTypeArgument(getClass()
                , DatagramPacketDecoderComponent.class);
        try {
            if(this.constructor == null) {
                this.constructor = aClass.getConstructor(byte[].class);
            }
        } catch (Exception e) {
            throw new ProtocolException("找不到构造函数["+aClass.getSimpleName()+"(byte[].class)], 请增加对应的构造函数或者自定义解码", e.getCause());
        }

        return aClass;
    }

    protected class UdpServerWrapper extends AbstractUdpServer {

        public UdpServerWrapper(int port) {
            super(port);
        }

        public UdpServerWrapper(ConnectProperties config) {
            super(config);
        }

        @Override
        public ChannelInboundHandlerAdapter getMessageDecoder() {
            return DatagramPacketDecoderComponent.this.getMessageDecoder();
        }
    }

    @ChannelHandler.Sharable
    protected class DatagramPacketSimpleHandle extends SimpleChannelInboundHandler<DatagramPacket> {

        @Override
        protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {
            final M decode = DatagramPacketDecoderComponent.this.proxy(ctx, msg);
            if(decode != null) {
                ctx.fireChannelRead(msg);
            }
        }
    }
}
